<?php

namespace App\Http\Middleware;

use Closure;
use App\Facades\SmsCode as SmsCodeService;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
use Illuminate\Contracts\Auth\Factory as Auth;

class SmsCode
{

    /**
     * The authentication factory instance.
     *
     * @var Auth
     */
    protected $auth;

    /**
     * Create a new middleware instance.
     *
     * @param  Auth $auth
     *
     * @return void
     */
    public function __construct(Auth $auth)
    {
        $this->auth = $auth;
    }

    /**
     * 短信验证码中间件
     * 向当前登录用户发送短信验证码, 用于验证当前用户操作
     * 必须在已登录时使用
     *
     * @param Request $request
     * @param Closure $next
     * @param null $guard
     * @param string $codeKey
     *
     * @return mixed
     * @throws AuthenticationException
     * @throws ValidationException
     */
    public function handle(Request $request, Closure $next, $guard = null, $codeKey = 'sms_code')
    {
        $this->authenticate($guard);

        $code = $request->input($codeKey);

        if (!$code) {
            throw ValidationException::withMessages([
                $codeKey => '验证码不能为空'
            ]);
        }

        $mobile = $this->guard($guard)->user()->mobile;

        if (!$check = SmsCodeService::check($mobile, $code)) {
            throw ValidationException::withMessages([
                $codeKey => '验证码不正确'
            ]);
        }

        $response = $next($request);

        if ($response->isSuccessful() || ($response->isRedirection() && is_null($response->exception))) {
            SmsCodeService::forget($mobile);
        }


        return $response;
    }

    /**
     * 返回guard实例
     *
     * @param null $guard
     *
     * @return Guard|\App\Models\AbstractUser
     */
    protected function guard($guard = null)
    {
        return $this->auth->guard($guard);
    }

    /**
     * 验证是否登录
     *
     * @param null $guard
     *
     * @throws AuthenticationException
     */
    protected function authenticate($guard = null)
    {
        if (!$this->guard($guard)->check()) {
            throw new AuthenticationException('Unauthenticated.', $guard ? [$guard] : null);
        }
    }
}
